'''
Created on 18/08/2009

@author: Tony Allan
'''
import unittest

from datastore.uri import *
from datastore.resource import *

CONFIGURATION = """<?xml version='1.0' encoding='UTF-8'?>
<resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://yarra.googlecode.com/files/resource-1.0.xsd">

    <!-- 
    Usage notes:
    1. Don't copy this note to subsequent files!
    2. configuration.xml replaces the manifest and all uri-definition files.
    3. Any initial or reference data can be included in this file.
    4. Uri() will clean-up any whitespace in URI elements.
    5. Whitespace will also be stripped from the one line title.
    6. The format of modules files and tasks is unchanged, although they are 
       in a different place compared to manifest.xml
    7. This is a package definition file. One per package.
    -->
    <metadata>
        <item key="datastore:resource/type" type="yarra:type/uri">package:type/configuration</item>
        <item key="dc:title" type="yarra:type/string">Datastore package configuration</item>
        <item key="dc:description" type="yarra:type/string">
            The datastore package is responsible for managing resources, 
            persistence and uri's.
            
            The Resource class is the primary unit of storage. It contains python 
            variables that include dict, list, tuple and most basic data types.
            Data can be nested  to create whatever structure is required.
            A Resource can be serialised to XML for storage in the database.
            A Resource also contains metadata.
            
            Datastore manages persistence of Resources. It saves the content of 
            the Resource in the database along with any metadata that is included 
            in the Resource.
            
            A uri is used to specify all identifiers in data and to name things.
            Uri's are defined in a configuration file in each package.
        </item>
        <item key="yarra:version" type="yarra:type/string">0.1</item>
    </metadata>

    <content>
        <list key="package:manifest/modules">
            <dict>
                <item key="package:filename" type="yarra:type/string">resource.py</item>
                <item key="package:startup" type="yarra:type/boolean">True</item>
            </dict>
            <dict>
                <item key="package:filename" type="yarra:type/string">resourcetest.py</item>
                <item key="package:startup" type="yarra:type/boolean">False</item>
            </dict>     
            <dict>
                <item key="package:filename" type="yarra:type/string">database.py</item>
                <item key="package:startup" type="yarra:type/boolean">True</item>
            </dict>                                                 
            <dict>
                <item key="package:filename" type="yarra:type/string">databasetest.py</item>
                <item key="package:startup" type="yarra:type/boolean">False</item>
            </dict>     
            <dict>
                <item key="package:filename" type="yarra:type/string">uri.py</item>
                <item key="package:startup" type="yarra:type/boolean">False</item>
            </dict>                                             
            <dict>
                <item key="package:filename" type="yarra:type/string">uritest.py</item>
                <item key="package:startup" type="yarra:type/boolean">False</item>
            </dict>                                             
        </list>
        
        <list key="package:manifest/tasks"/>
        
        <list key="package:manifest/files">
            <item type="yarra:type/string">file one</item>
            <item type="yarra:type/string">file two</item>
        </list>

        <!-- Binding is used to create the namespaces list. It may be modified during package installation. -->
        <dict key="package:manifest/binding">
            <item key="term" type="yarra:type/uri">
                http://yarra-project.com/terms/</item>
            <item key="yarra" type="yarra:type/uri">
                http://yarra-project/terms/yarra/</item>
            <item key="dc" 
                 type="yarra:type/uri">
                http://purl.org/dc/elements/1.1/</item>
        </dict>
        
        <dict key="package:manifest/spaces">
            <!-- Each dict key is a uri, generally using a namespace to allow binding to a local base URI. -->
            <dict key="term:type/root">
                <item key="package:label" type="yarra:type/string">Resource Type - Root</item>
                <item key="package:definition" type="yarra:type/string">
                    The resource type for the root datastore node.
                </item>
                <item key="package:reference" 
                     type="yarra:type/uri">http://???</item>
            </dict>
            <dict key="term:node-id">
                <item key="package:label" type="yarra:type/string">Node Identifier</item>
                <item key="package:definition" type="yarra:type/string">
                    The identifier for the type 4 (random) UUID metadata element
                    of the root resource.
                </item>
            </dict>
            <dict key="term:resource/type">
                <item key="package:label" type="yarra:type/string">Resource Metadata - Resource Type</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource type key.
                </item>
            </dict>
            
            <!-- Yarra URI's -->
            <dict key="yarra:version">
                <item key="package:label" type="yarra:type/string">Version</item>
                <item key="package:definition" type="yarra:type/string">
                    The version of the item being described.
                </item>
            </dict>
            <dict key="yarra:type/none">
                <item key="package:label" type="yarra:type/string">Resource Data Type - none</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.NoneType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#index-564</item>
            </dict>
            <dict key="yarra:type/boolean">
                <item key="package:label" type="yarra:type/string">Resource Data Type - boolean</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.BooleanType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/reference/datamodel.html#index-781</item>
            </dict>
            <dict key="yarra:type/int">
                <item key="package:label" type="yarra:type/string">Resource Data Type - int</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.IntType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#numeric-types-int-float-long-complex</item>
            </dict>
            <dict key="yarra:type/long">
                <item key="package:label" type="yarra:type/string">Resource Data Type - long</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.LongType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#numeric-types-int-float-long-complex</item>
            </dict>
            <dict key="yarra:type/float">
                <item key="package:label" type="yarra:type/string">Resource Data Type - float</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.FloatType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#numeric-types-int-float-long-complex</item>
            </dict>
            <dict key="yarra:type/unicode">
                <item key="package:label" type="yarra:type/string">Resource Data Type - unicode</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.UnicodeType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-buffer-xrange</item>
            </dict>
            <dict key="yarra:type/string">
                <item key="package:label" type="yarra:type/string">Resource Data Type - string</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to Python types.StringType.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.python.org/doc/2.6.2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-buffer-xrange</item>
            </dict>
            <dict key="yarra:type/resource">
                <item key="package:label" type="yarra:type/string">Resource Data Type - resource</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type corresponding to class Resource().
                </item>
            </dict>
            <dict key="yarra:type/uri">
                <item key="package:label" type="yarra:type/string">Resource Data Type - uri</item>
                <item key="package:definition" type="yarra:type/string">
                    Resource Data Type for a string that contains a fully qualified URI.
                </item>
            </dict>
            <!-- 
            URI definitions for the basic Dublin Core elements.
            For DC elements (see http://dublincore.org/documents/dcmi-terms/), the definition includes: 
            URI (key), Label, Definition, Reference (comment) URI, Type of Term, Version URI, Note. 
            The last three items are specific to DC.
            -->
            <dict key="dc:contributor">
                <item key="package:label" type="yarra:type/string">DC - Contributor</item>
                <item key="package:definition" type="yarra:type/string">
                    An entity responsible for making contributions to the resource.
                   
                    Examples of a Contributor include a person, an organization, or a service. 
                    Typically, the name of a Contributor should be used to indicate the entity.
                </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#contributor-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:coverage">
                <item key="package:label" type="yarra:type/string">DC - Coverage</item>
                <item key="package:definition" type="yarra:type/string">
                    The spatial or temporal topic of the resource, the spatial applicability 
                    of the resource, or the jurisdiction under which the resource is relevant.
                    
                    Spatial topic and spatial applicability may be a named place or a location 
                    specified by its geographic coordinates. Temporal topic may be a named period, 
                    date, or date range. A jurisdiction may be a named administrative entity or a 
                    geographic place to which the resource applies. Recommended best practice is to 
                    use a controlled vocabulary such as the Thesaurus of Geographic Names [TGN]. 
                    Where appropriate, named places or time periods can be used in preference to 
                    numeric identifiers such as sets of coordinates or date ranges.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.getty.edu/research/tools/vocabulary/tgn/index.html</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#coverage-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:creator">
                <item key="package:label" type="yarra:type/string">DC - Creator</item>
                <item key="package:definition" type="yarra:type/string">
                    An entity primarily responsible for making the resource.
                    
                    Examples of a Creator include a person, an organization, or a service. 
                    Typically, the name of a Creator should be used to indicate the entity.
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.getty.edu/research/tools/vocabulary/tgn/index.html</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#creator-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:date">
                <item key="package:label" type="yarra:type/string">DC - Date</item>
                <item key="package:definition" type="yarra:type/string">
                    A point or period of time associated with an event in the lifecycle 
                    of the resource.
                    
                    Date may be used to express temporal information at any level of 
                    granularity. Recommended best practice is to use an encoding scheme, 
                    such as the W3CDTF profile of ISO 8601 [W3CDTF].
                </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.w3.org/TR/NOTE-datetime</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#date-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:description">
                <item key="package:label" type="yarra:type/string">DC - Description</item>
                <item key="package:definition" type="yarra:type/string">
                    An account of the resource.
                    
                    Description may include but is not limited to: an abstract, a table 
                    of contents, a graphical representation, or a free-text account of 
                    the resource.
                </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#description-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/).
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:format">
                <item key="package:label" type="yarra:type/string">DC - Format</item>
                <item key="package:definition" type="yarra:type/string">
                    The file format, physical medium, or dimensions of the resource.
                    
                    Examples of dimensions include size and duration. Recommended best 
                    practice is to use a controlled vocabulary such as the list of Internet 
                    Media Types [MIME].
                    </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.iana.org/assignments/media-types/</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#format-007</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/).
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:identifier">
                <item key="package:label" type="yarra:type/string">DC - Identifier</item>
                <item key="package:definition" type="yarra:type/string">
                    An unambiguous reference to the resource within a given context.
                    
                    Recommended best practice is to identify the resource by means of a 
                    string conforming to a formal identification system.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#identifier-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:language">
                <item key="package:label" type="yarra:type/string">DC - Language</item>
                <item key="package:definition" type="yarra:type/string">
                    A language of the resource.
                    
                    Recommended best practice is to use a controlled vocabulary such as 
                    RFC 4646 [RFC4646].
                    </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://www.ietf.org/rfc/rfc4646.txt</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#language-007</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:publisher">
                <item key="package:label" type="yarra:type/string">DC - Publisher</item>
                <item key="package:definition" type="yarra:type/string">
                    An entity responsible for making the resource available.
                    
                    Examples of a Publisher include a person, an organization, or a 
                    service. Typically, the name of a Publisher should be used to 
                    indicate the entity.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#publisher-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:relation">
                <item key="package:label" type="yarra:type/string">DC - Relation</item>
                <item key="package:definition" type="yarra:type/string">
                    A related resource.

                    Recommended best practice is to identify the related resource 
                    by means of a string conforming to a formal identification system.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#relation-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:rights">
                <item key="package:label" type="yarra:type/string">DC - Rights</item>
                <item key="package:definition" type="yarra:type/string">
                    Information about rights held in and over the resource.
                    
                    Typically, rights information includes a statement about various 
                    property rights associated with the resource, including intellectual 
                    property rights.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#rights-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:source">
                <item key="package:label" type="yarra:type/string">DC - Source</item>
                <item key="package:definition" type="yarra:type/string">
                    A related resource from which the described resource is derived.

                    The described resource may be derived from the related resource in 
                    whole or in part. Recommended best practice is to identify the related 
                    resource by means of a string conforming to a formal identification 
                    system.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#source-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:subject">
                <item key="package:label" type="yarra:type/string">DC - Subject</item>
                <item key="package:definition" type="yarra:type/string">
                    The topic of the resource.

                    Typically, the subject will be represented using keywords, key 
                    phrases, or classification codes. Recommended best practice is 
                    to use a controlled vocabulary. To describe the spatial or temporal 
                    topic of the resource, use the Coverage element.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#subject-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:title">
                <item key="package:label" type="yarra:type/string">DC - Title</item>
                <item key="package:definition" type="yarra:type/string">
                    A name given to the resource.
                    </item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#title-006</item>
                <item key="package:note" 
                     type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/). 
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>
            <dict key="dc:type">
                <item key="package:label" type="yarra:type/string">DC - Type</item>
                <item key="package:definition" type="yarra:type/string">
                    The nature or genre of the resource.

                    Recommended best practice is to use a controlled vocabulary 
                    such as the DCMI Type Vocabulary [DCMITYPE]. To describe the file 
                    format, physical medium, or dimensions of the resource, use the 
                    Format element.
                    </item>
                <item key="package:reference" type="yarra:type/uri">
                    http://dublincore.org/documents/dcmi-type-vocabulary/</item>
                <item key="package:termtype" type="yarra:type/string">Property</item>
                <item key="package:version" type="yarra:type/uri">
                    http://dublincore.org/usage/terms/history/#type-006</item>
                <item key="package:note" type="yarra:type/string">
                    A second property with the same name as this property has been declared in the dcterms: namespace (http://purl.org/dc/terms/).
                    See the Introduction to the document "DCMI Metadata Terms" (http://dublincore.org/documents/dcmi-terms/) for an explanation.
                </item>
            </dict>

        </dict>
    </content>
</resource>
"""
            
class UriTest(unittest.TestCase):

    def setUp(self):
        self.res = Resource(CONFIGURATION)
        Uri.namespaces['a'] = 'http://helloworld.com/'
        
    def tearDown(self):
        pass

    def uri_eq(self, a, b):
        '''Convenience method. '''
        self.assertEqual(a, b, "URIs not equal: %s  %s" % (str(a), str(b)))

    def uri_ne(self, a, b):
        '''Convenience method. '''
        self.assertNotEqual(a, b, "URIs equal (should be different): %s  %s" % (str(a), str(b)))

    def uri_eq_str(self, a, b):
        '''Convenience method. '''
        self.assertEqual(str(a), str(b), "URIs not string equal: %s  %s" % (str(a), str(b)))

    def test_uri_example_01(self):
        '''[uri] Verify that the example in Uri() actually works.'''
        uri = Uri('internal:')
        #print(uri.type.root)
        if uri.type.root == 'http://node.internal/type/root':
            #print('hello world!')
            assert True
        else:
            assert False

    def test_case_01_construction(self):
        """[uri] basic URI construction."""
        uri = Uri('http://aaa/')
        self.uri_eq_str(uri, 'http://aaa/')
        self.uri_eq_str(uri.a, 'http://aaa/a')
        self.uri_eq_str(uri.a.b, 'http://aaa/a/b')
        self.uri_eq_str(uri.c.a, 'http://aaa/c/a')
        self.uri_eq_str(uri.a.b, 'http://aaa/a/b')

    def test_case_01a_add(self):
        """[uri] basic URI construction using add."""
        uri = Uri('http://aaa/')
        self.uri_eq_str(uri, 'http://aaa/')
        self.uri_eq_str(uri.add('a'), 'http://aaa/a')
        self.uri_eq_str(uri.add('a').add('b'), 'http://aaa/a/b')
        self.uri_eq_str(uri.add('c').add('a'), 'http://aaa/c/a')
        self.uri_eq_str(uri.add('a').add('b'), 'http://aaa/a/b')

    def test_case_02_comparison(self):
        """[uri] URI comparison (single URI)."""
        uri = Uri('http://aaa/') 
        assert     uri == uri
        assert not uri < uri
        assert not uri > uri  

    def test_case_02a_comparison(self):
        """[uri] URI comparison (with a string of the URI)."""
        uri = Uri('http://aaa/') 
        assert     uri == 'http://aaa/'
        assert not uri < 'http://aaa/'
        assert not uri > 'http://aaa/'  

    def test_case_02b_comparison(self):
        """[uri] URI comparison (single URI) a."""
        uri = Uri('http://aaa/') 
        assert     uri.a == uri.a
        assert     uri.a < uri.b
        assert     uri.b > uri.a  

    def test_case_02c_comparison(self):
        """[uri] URI comparison (with a copy of the URI)."""
        uri = Uri('http://aaa/') 
        assert     uri == uri.uri_copy()
        assert not uri < uri.uri_copy()
        assert not uri > uri.uri_copy()  

    def test_case_03_comparison(self):
        """[uri] URI comparison (uri.a)."""
        uri = Uri('http://aaa/') 
        assert not uri.a == uri.b
        assert     uri.a < uri.b
        assert not uri.a > uri.b  

    def test_case_04_comparison(self):
        """[uri] URI comparison (uri.aa)."""
        uri = Uri('http://aaa/') 
        assert not uri.a == uri.aa
        assert     uri.a < uri.aa
        assert not uri.a > uri.aa  

    def test_case_05_comparison(self):
        """[uri] URI comparison (uri.a.b)."""
        uri = Uri('http://aaa/') 
        assert not uri.a == uri.a.b
        assert     uri.a < uri.a.b
        assert not uri.a > uri.a.b  

    def test_case_06_comparison(self):
        """[uri] URI comparison (uri.c uri.a.b)."""
        uri = Uri('http://aaa/') 
        assert not uri.c == uri.a.b
        assert not uri.c < uri.a.b
        assert     uri.c > uri.a.b  

    def test_case_07_length(self):
        """[uri] URI length."""
        uri = Uri('http://aaa/') 
        assert len(uri) == 11
        assert len(uri.a) == 12
        assert len(uri.a.b) == 14
        uri = Uri() 
        assert len(uri) == 0

    def test_case_08_init(self):
        """[uri] init."""
        uri = Uri(uri=None)
        self.uri_eq_str(uri, '')
        
        uri = Uri(uri='uri')
        self.uri_eq_str(uri, 'uri')
        
        uri = Uri(uri=None)
        self.uri_eq_str(uri, '')
        
        uri = Uri(uri=None)
        self.uri_eq_str(uri, '')

        uri = Uri(uri='dc:a')
        self.uri_eq_str(uri, 'dc:a')

    def uri_eq_list(self, a, b):
        ''' Convenience method. 'a' must be a URI as a string.'''
        u = Uri(a).split()
        self.assertEqual(u, b, "URIs split lists not equal: %s  %s" % (u, b))
        if u is not None:
            j = '/'.join(u)
            self.assertEqual(j.lower(), a.lower(),
                "URIs when rejoined not equal (a): %s  %s" % (j.lower(), a.lower()))

    def test_case_09_split(self):
        """[uri] split."""
        self.uri_eq_list(None, None)
        self.uri_eq_list('', None)
        self.uri_eq_list('/', ['', ''])
        self.uri_eq_list('//', ['', '', ''])
        self.uri_eq_list('/a', ['', 'a'])
        self.uri_eq_list('/a/', ['', 'a', ''])
        self.uri_eq_list('aaa', ['aaa'])
        self.uri_eq_list('aaa/', ['aaa', ''])
        self.uri_eq_list('aaa/bbb', ['aaa', 'bbb'])
        self.uri_eq_list('http:', ['http:'])
        self.uri_eq_list('http:a', ['http:a'])
        self.uri_eq_list('http:a/', ['http:a', '']) # parse: 'http', '', 'a/'
        self.uri_eq_list('http:a/a', ['http:a', 'a'])
        self.uri_eq_list('http://', ['http:', '', ''])
        self.uri_eq_list('http://aaa.com', ['http://aaa.com'])
        self.uri_eq_list('http://aaa.com/', ['http://aaa.com', ''])
        self.uri_eq_list('http://aaa.com:80', ['http://aaa.com:80'])
        self.uri_eq_list('http://aaa.com:80/', ['http://aaa.com:80', ''])
        self.uri_eq_list('http://aaa.com:80/aa/bb/cc/dd/ee', ['http://aaa.com:80', 'aa', 'bb', 'cc', 'dd', 'ee'])
        self.uri_eq_list('http://aaa.com:80/aa/bb/cc/dd/ee/', ['http://aaa.com:80', 'aa', 'bb', 'cc', 'dd', 'ee', ''])
        self.uri_eq_list('z:', ['z:'])
        self.uri_eq_list('z:a', ['z:a'])
        self.uri_eq_list('z://', ['z:', '', ''])
        self.uri_eq_list('z://aaa.com', ['z://aaa.com']) # was ['a:', '', 'aaa.com'] parse: 'a', '', '//aaa.com'
        self.uri_eq_list('z://aaa.com/', ['z://aaa.com', '']) # was ['a:', '', 'aaa.com', '']
        self.uri_eq_list('ftp://aaa.com', ['ftp://aaa.com'])
        self.uri_eq_list('ftp://aaa.com/', ['ftp://aaa.com', ''])
        self.uri_eq_list('file:///aaa.com', ['file:', '', '', 'aaa.com']) # parse: 'file:', '', '', 'aaa.com'
        self.uri_eq_list('file:///aaa.com/', ['file:', '', '', 'aaa.com', ''])
        self.uri_eq_list('..', ['..'])
        self.uri_eq_list('../..', ['..', '..'])
        self.uri_eq_list('./.', ['.', '.'])
        self.uri_eq_list('./this:that', ['.', 'this:that'])
        self.uri_eq_list('http://10.0.1.50', ['http://10.0.1.50'])
        self.uri_eq_list('http://10.0.1.50/', ['http://10.0.1.50', ''])
        self.uri_eq_list('https://aaa.com', ['https://aaa.com'])
        self.uri_eq_list('https://aaa.com/', ['https://aaa.com', ''])
        self.uri_eq_list('https://aaa.com:80', ['https://aaa.com:80'])
        self.uri_eq_list('https://aaa.com:80/', ['https://aaa.com:80', ''])
        self.uri_eq_list('https://aaa.com:80/aa/bb/cc/dd/ee', ['https://aaa.com:80', 'aa', 'bb', 'cc', 'dd', 'ee'])
        self.uri_eq_list('http://aaa.com:80/aa%20', ['http://aaa.com:80', 'aa%20'])
        self.uri_eq_list('HTTP://aaa.com:80/aa', ['http://aaa.com:80', 'aa'])
        self.uri_eq_list('HTTP://aaa.com:80/Aa', ['http://aaa.com:80', 'Aa'])
        self.uri_eq_list('http://aaa.com:aa/aa', ['http://aaa.com:aa', 'aa'])

    def uri_eq_list2(self, a, b):
        ''' Convenience method. 'a' must be a URI as a string.'''
        u = Uri(a).split2()
        self.assertEqual(u, b, "URIs split lists not equal: %s  %s" % (u, b))
        if u is not None:
            j = ''.join(u)
            self.assertEqual(j.lower(), a.lower(),
                "URIs when rejoined not equal (a): %s  %s" % (j.lower(), a.lower()))

#    def uri_exception_list2(self, a):
#        ''' Convenience method. 'a' must be a URI as a string.'''
#        try:
#            u = Uri(a).split2()
#            assert False
#        except InvalidURLException:
#            self.assertEqual(str(sys.exc_info()[1]), a)

    def test_case_09_split2(self):
        """[uri] split2."""
        self.uri_eq_list2(None, None)
        self.uri_eq_list2('', None)
        self.uri_eq_list2('/', ['/'])
        self.uri_eq_list2('//', ['/', '/'])
        self.uri_eq_list2('/a', ['/', 'a'])
        self.uri_eq_list2('/a/', ['/', 'a/'])
        self.uri_eq_list2('aaa', ['aaa'])
        self.uri_eq_list2('aaa/', ['aaa/'])
        self.uri_eq_list2('aaa/bbb', ['aaa/', 'bbb'])
        #self.uri_exception_list2('http:')           # Not valid HTTP
        #self.uri_exception_list2('http:a')          # Not valid HTTP
        #self.uri_exception_list2('http:a/')         # Not valid HTTP
        #self.uri_exception_list2('http:a/a')        # Not valid HTTP
        self.uri_eq_list2('http://', ['http://'])
        self.uri_eq_list2('http://aaa.com', ['http://aaa.com'])
        self.uri_eq_list2('http://aaa.com/', ['http://aaa.com/'])
        self.uri_eq_list2('http://aaa.com:80', ['http://aaa.com:80'])
        self.uri_eq_list2('http://aaa.com:80/', ['http://aaa.com:80/'])
        self.uri_eq_list2('http://aaa.com:80#fred', ['http://aaa.com:80', '#fred'])
        self.uri_eq_list2('http://aaa.com:80/#fred', ['http://aaa.com:80/', '#fred'])
        self.uri_eq_list2('http://aaa.com:80/aaa/#fred', ['http://aaa.com:80/', 'aaa/', '#fred'])
        self.uri_eq_list2('http://aaa.com:80/aa/bb/cc/dd/ee', ['http://aaa.com:80/', 'aa/', 'bb/', 'cc/', 'dd/', 'ee'])
        self.uri_eq_list2('http://aaa.com:80/aa/bb/cc/dd/ee/', ['http://aaa.com:80/', 'aa/', 'bb/', 'cc/', 'dd/', 'ee/'])
        self.uri_eq_list2('z:', ['z:'])
        self.uri_eq_list2('z:a', ['z:', 'a'])
        # if the uri cannot be split, it is returned as itself.
        self.uri_eq_list2('z://', ['z://'])                      # was ['a:/', '/'] Works but is silly
        self.uri_eq_list2('z://aaa.com', ['z://aaa.com'])        # was ['a:/', '/', 'aaa.com'] Works but is silly
        self.uri_eq_list2('z://aaa.com/', ['z://aaa.com/'])      # was ['a:/', '/', 'aaa.com/'] Works but is silly
        self.uri_eq_list2('z://aaa.com/a/', ['z://aaa.com/a/'])
        self.uri_eq_list2('ftp://aaa.com', ['ftp://aaa.com'])
        self.uri_eq_list2('ftp://aaa.com/', ['ftp://aaa.com/'])
        # includes examples from http://en.wikipedia.org/wiki/File_URI_scheme
        self.uri_eq_list2('file:///aaa.com', ['file://', '/', 'aaa.com'])
        self.uri_eq_list2('file:///aaa.com/', ['file://', '/', 'aaa.com/'])
        self.uri_eq_list2('file://host/path', ['file://host/', 'path'])
        self.uri_eq_list2('file://localhost/etc/fstab', ['file://localhost/', 'etc/', 'fstab'])
        self.uri_eq_list2('file:///etc/fstab', ['file://', '/', 'etc/', 'fstab'])
        self.uri_eq_list2('file://localhost/c|/WINDOWS/clock.avi', ['file://localhost/', 'c|/', 'WINDOWS/', 'clock.avi'])
        self.uri_eq_list2('file:///c|/WINDOWS/clock.avi',          ['file://', '/', 'c|/', 'WINDOWS/', 'clock.avi'])
        self.uri_eq_list2('file://localhost/c:/WINDOWS/clock.avi', ['file://localhost/', 'c:/', 'WINDOWS/', 'clock.avi'])
        self.uri_eq_list2('file:///c:/WINDOWS/clock.avi',          ['file://', '/', 'c:/', 'WINDOWS/', 'clock.avi'])
        #
        self.uri_eq_list2('..', ['..'])
        self.uri_eq_list2('../..', ['../', '..'])
        self.uri_eq_list2('./.', ['./', '.'])
        self.uri_eq_list2('./this:that', ['./', 'this:that'])
        #
        self.uri_eq_list2('http://10.0.1.50', ['http://10.0.1.50'])
        self.uri_eq_list2('http://10.0.1.50/', ['http://10.0.1.50/'])
        self.uri_eq_list2('https://aaa.com', ['https://aaa.com'])
        self.uri_eq_list2('https://aaa.com/', ['https://aaa.com/'])
        self.uri_eq_list2('https://aaa.com:80', ['https://aaa.com:80'])
        self.uri_eq_list2('https://aaa.com:80/', ['https://aaa.com:80/'])
        self.uri_eq_list2('https://aaa.com:80/aa/bb/cc/dd/ee', ['https://aaa.com:80/', 'aa/', 'bb/', 'cc/', 'dd/', 'ee'])
        self.uri_eq_list2('http://aaa.com:80/aa%20', ['http://aaa.com:80/', 'aa%20'])
        self.uri_eq_list2('HTTP://aaa.com:80/aa', ['http://aaa.com:80/', 'aa'])
        self.uri_eq_list2('HTTP://aaa.com:80/Aa', ['http://aaa.com:80/', 'Aa'])
        self.uri_eq_list2('http://aaa.com:aa/aa', ['http://aaa.com:aa/', 'aa'])
        # examples from http://en.wikipedia.org/wiki/Uniform_Resource_Name
        self.uri_eq_list2('urn:isbn:0451450523', ['urn:', 'isbn:', '0451450523'])
        self.uri_eq_list2('urn:isan:0000-0000-9E59-0000-O-0000-0000-2', ['urn:', 'isan:', '0000-0000-9E59-0000-O-0000-0000-2'])
        self.uri_eq_list2('urn:issn:0167-6423', ['urn:', 'issn:', '0167-6423'])
        self.uri_eq_list2('urn:ietf:rfc:2648', ['urn:', 'ietf:', 'rfc:', '2648'])
        self.uri_eq_list2('urn:mpeg:mpeg7:schema:2001', ['urn:', 'mpeg:', 'mpeg7:', 'schema:', '2001'])
        self.uri_eq_list2('urn:oid:2.16.840', ['urn:', 'oid:', '2.16.840'])
        self.uri_eq_list2('urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66', ['urn:', 'uuid:', '6e8bc430-9c3a-11d9-9669-0800200c9a66'])
        self.uri_eq_list2('urn:uci:I001+SBSi-B10000083052', ['urn:', 'uci:', 'I001+SBSi-B10000083052'])
        self.uri_eq_list2('urn:www.agxml.org:schemas:all:2:0', ['urn:', 'www.agxml.org:', 'schemas:', 'all:', '2:', '0'])
        self.uri_eq_list2('urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C', ['urn:', 'sha1:', 'YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C'])
        self.uri_eq_list2('urn:tree:tiger:BL5OM7M75DWHAXMFZFJ23MU3LVMRXKFO6HTGUTY', ['urn:', 'tree:', 'tiger:', 'BL5OM7M75DWHAXMFZFJ23MU3LVMRXKFO6HTGUTY'])
        self.uri_eq_list2('mailto:tony.allan@dse.vic.gov.au', ['mailto:', 'tony.allan@dse.vic.gov.au'])
        self.uri_eq_list2('planning:spear:S001234T:app', ['planning:', 'spear:S001234T:app'])


    def test_case_10_addition(self):
        """[uri] addition."""
        uri1 = Uri('http://aaa')
        uri2 = Uri()
        self.uri_eq_str(uri1 + uri2.a.b.c + uri2.d, 'http://aaa/a/b/c/d')
        
        uri1 = Uri('http://aaa/')
        uri2 = Uri()
        self.uri_eq_str(uri1 + uri2.a.b.c + uri2.d, 'http://aaa/a/b/c/d')

    def test_case_11_match(self):
        """[uri] match."""
        uri = Uri('http://yarra-project.com/element/datastore/')
        assert uri.a.b.match(uri.a)
        assert uri.a.b.match(uri.a.b)
        assert not uri.a.b.match(uri.b.a)
        assert not uri.a.match(uri.a.b)
        assert not Uri().match(uri.a.b)
        assert Uri().match(Uri())
        assert uri.type.root.match('http://yarra-project.com/element/datastore/type/')
            
    def test_case_12_collection(self):
        """[uri] collection."""
        uri = Uri('http://aaa.com/')
        self.uri_eq_str(uri.collection(), 'http://aaa.com/')
        self.uri_eq_str(uri.a.b.c.collection(), 'http://aaa.com/a/b/c/')
        uri2 = Uri('http://eee.edu.au/d/e/f')
        self.uri_eq_str(uri2, 'http://eee.edu.au/d/e/f')
        self.uri_eq_str(uri2.collection().collection().collection().collection(), 'http://eee.edu.au/d/e/f/')
        self.uri_eq_str(uri2.a.b.c, 'http://eee.edu.au/d/e/f/a/b/c')
        self.uri_eq_str(uri2.a.collection().b.collection().c.collection(), 'http://eee.edu.au/d/e/f/a/b/c/')
        uri3 = Uri()
        self.uri_eq_str(uri3, '')
        self.uri_eq_str(uri3.collection(), '/')
            
    def test_case_13_collection(self):
        """[uri] collection removal."""
        uri = Uri('http://aaa.net/')
        uri.collection(False)
        self.uri_eq_str(uri, 'http://aaa.net')
        uri3 = Uri()
        self.uri_eq_str(uri3, '')
        uri3.collection(False)
        self.uri_eq_str(uri3, '')
        uri = Uri('z:')
        uri.collection(False)
        self.uri_eq_str(uri, 'z:')
        uri = Uri('z:')
        uri.collection(True)
        self.uri_eq_str(uri, 'z:/')
        uri = Uri('a:')
        uri.collection(False)
        self.uri_eq_str(uri, 'http://helloworld.com')                
    
    def test_case_14_namespaces(self):
        """[uri] namespaces."""
        uri = Uri(uri='yarra:a/b')
        self.uri_eq_str(uri, 'yarra:a/b')
        uri = Uri(uri='xyz:a/b')
        self.uri_eq_str(uri, 'xyz:a/b')
        uri = Uri(uri='yarra:')
        self.uri_eq_str(uri, 'yarra:')

    def test_case_15_url(self):
        """[uri] url()."""
        uri = Uri('http://aaa.com:80/aa/bb/cc/dd/ee')
        url = uri.url()
        self.assertEqual(url.scheme, 'http', "Scheme not 'http'")
        self.assertEqual(url.netloc, 'aaa.com:80', "Netloc not 'aaa.com:80'")
        self.assertEqual(url.path, '/aa/bb/cc/dd/ee', "Path not '/aa/bb/cc/dd/ee'")
        self.assertEqual(url.hostname, 'aaa.com', "Hostname not 'aaa.com'")
        self.assertEqual(url.port, 80, "Port not the integer '80'")

    def test_case_15_url_scheme_a(self):
        """[uri] url() with an unsupported scheme"""
        uri = Uri('z://aaa.com:80/aa/bb/cc/dd/ee')
        url = uri.url()
        self.assertEqual(url.scheme, 'z', "Scheme is not 'a'.")
        self.assertEqual(url.netloc, 'aaa.com:80', "Netloc not 'aaa.com:80'")
        self.assertEqual(url.path, '/aa/bb/cc/dd/ee', "Path not '/aa/bb/cc/dd/ee'")
        self.assertEqual(url.hostname, 'aaa.com', "Hostname not 'aaa.com'")
        self.assertEqual(url.port, 80, "Port not the integer '80'")

    def test_case_16_is_collection(self):
        '''[uri] is_collection'''
        uri = Uri('http://aaa.com/asdf/')
        self.assertTrue(uri.is_collection())
        uri = Uri('a:')
        self.assertTrue(uri.is_collection())        
        
    def test_case_17_full_uri_case_1(self):
        '''[uri] test full_uri prefix exists'''
        # A namespace URI is always just appended to its parts. Include a slash if needed.
        uri = Uri('a:')
        self.assertEqual(uri.full_uri(), 'http://helloworld.com/')
        self.assertEqual(uri.a.full_uri(), 'http://helloworld.com/a')

    def test_case_18_full_uri_case_2(self):
        '''[uri] test full_uri prefix plus path'''
        # A namespace URI is always just appended to its parts. Include a slash if needed.

        uri = Uri('a:b')
        self.assertEqual(uri.full_uri(), 'http://helloworld.com/b')

    def test_case_19_full_uri_case_3(self):
        '''[uri] test full_uri prefix doesn't exist'''
        # A namespace URI is always just appended to its parts. Include a slash if needed.

        uri = Uri('b:')
        self.assertEqual(uri.full_uri(), 'b:')                

    def test_case_19a_full_uri_case_4(self):
        '''[uri] test full_uri prefix term exists'''
        # A namespace URI is always just appended to its parts. Include a slash if needed.

        uri = Uri('term:a')
        self.assertEqual(uri.full_uri(), 'http://node.internal/data_dictionary/a')                

    def test_case_20_full_as_uri(self):
        '''[uri] test full'''
        uri = Uri('a:b')
        self.assertEqual(str(uri.full()), uri.full_uri())                

    def test_case_21_fragmented(self):
        '''[uri] test fragmented'''
        uri1 = Uri('a:b#c')
        u1, f1 = uri1.fragmented()
        uri2 = Uri('a:b#')
        u2, f2 = uri2.fragmented()
        uri3 = Uri('a:b')
        u3, f3 = uri3.fragmented()
        uri4 = Uri()
        self.assertEqual(str(uri1), str(u1) + '#' + f1)
        self.assertEqual(str(uri2), str(u2) + '#')
        self.assertEqual(f2, '')
        self.assertEqual(str(uri3), str(u3))
        self.assertEqual(f3, None)
        self.assertEqual(uri4.fragmented(), (None, None))

    def test_case_22_without_fragment(self):
        '''[uri] test without_fragment'''
        uri = Uri('a:b#c')
        u, f = uri.fragmented()
        self.assertEqual(str(uri.without_fragment()), str(u))

    def test_case_23_fragment(self):
        '''[uri] test fragment'''
        ns = {'a':'http://helloworld.com/'}
        uri = Uri('a:b#c')
        u, f = uri.fragmented()
        self.assertEqual(uri.fragment(), f)
    
    def test_case_24_add_side_effects(self):
        '''[uri] test side effects of add'''
        uri1a = Uri('internal:fred')
        uri1b = Uri('internal:fred')
        uri2a = Uri('harry')
        uri2b = Uri('harry')
        uri3a = Uri('internal:fred/harry')
        uri3b = Uri('internal:fred/harry')
        uri3c = Uri('internal:fred').add('harry')
        uri4a = uri1a + uri2a
        uri4x = uri1a + uri2b
        self.uri_eq(uri3a, uri4a)
        self.uri_eq(uri3a, uri4x)
        self.uri_eq(uri4a, uri4x)
        self.uri_eq(uri3c, uri4a)
        self.uri_eq(uri3c, uri4x)
    
    def test_case_25_more_add_side_effects(self):
        '''[uri] test more side effects of add'''
        uri1a = Uri('internal:fred')
        uri1b = Uri('internal:').add('fred')
        uri1c = Uri('internal:') + 'fred'
        uri2a = Uri('harry')
        uri2b = Uri('harry')
        uri3a = Uri('internal:fred/harry')
        uri3b = Uri('internal:').add('fred/harry')
        uri3c = Uri('internal:fred').add('harry')
        uri4a = uri1a + uri2a
        uri4x = uri1a + uri2b
        uri5x = uri1a + 'harry'
        uri6a = Uri('internal:abc/def/1')
        uri6b = Uri('internal:abc/def') + 1
        uri6c = Uri('internal:abc/def').add(1)
        self.uri_eq(uri1a, uri1b)
        self.uri_eq(uri1a, uri1c)
        self.uri_eq(uri3a, uri4a)
        self.uri_eq(uri3a, uri4x)
        self.uri_eq(uri4a, uri4x)
        self.uri_eq(uri3c, uri4a)
        self.uri_eq(uri3c, uri4x)
        self.uri_eq(uri3a, uri3b)
        self.uri_eq(uri3a, uri3c)
        self.uri_eq(uri4x, uri5x)
        self.uri_eq(uri6a, uri6b)
        self.uri_eq(uri6a, uri6c)
        uri7x = uri1a + '/' + 'harry'           # test incorrect construction
        self.uri_ne(uri4x, uri7x)               # should be not equal
        uri7x = Uri(str(uri1a) + '/' + 'harry')
        self.uri_eq(uri4x, uri7x)               # not recommended

    def test_case_26_test_whitespace_removal(self):
        '''[uri] test removal of whitespace'''
        # Uri's may have come from an XML file formatted using whitespace.
        uri1a = Uri('internal:fred')
        uri1b = Uri("""               internal:fred
                    """)
        uri1b = Uri('internal:').add('fred')
        uri1c = Uri('internal:').add("""
                fred
                """)
        uri1d = Uri('internal:') + """
                fred
                """
        self.uri_eq(uri1a, uri1b)
        self.uri_eq(uri1a, uri1c)
        self.uri_eq(uri1a, uri1d)
    
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()